package com.lagou.filter;

import org.apache.dubbo.common.constants.CommonConstants;
import org.apache.dubbo.common.extension.Activate;
import org.apache.dubbo.rpc.*;

import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;


@Activate(group = {CommonConstants.PROVIDER})
public class TPMonitorFilter implements Filter {

    private final List<InvokeTime> invokeTimes;

    public TPMonitorFilter() {
        invokeTimes = Collections.synchronizedList(new LinkedList<>());

        ScheduledExecutorService executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleWithFixedDelay(() -> {
            // 删除超过一分钟的数据;
            ArrayList<InvokeTime> fastShot = null;

            synchronized (invokeTimes){
                long current = System.currentTimeMillis();
                invokeTimes.removeIf(invokeTime -> current - invokeTime.getInvokeTime() > 60 * 1000L);
                fastShot  = new ArrayList<>(invokeTimes);
            }

            // 统计tp90, tp99;
            // 计数
            int count = fastShot.size();
            // 为空则跳过
            if (count == 0){
                System.out.println("最近一分钟内无请求");
                return;
            }

            // 排序， 取90%那个元素
            fastShot.sort(Comparator.comparingLong(InvokeTime::getCost));
            InvokeTime tp90 = fastShot.get((int) (0.9 * count));
            InvokeTime tp99 = fastShot.get((int) (0.99 * count));
            System.out.println("tp90:" + tp90.getCost() + "ms.   tp99:" + tp99.getCost() + "ms");


        },5, 5, TimeUnit.SECONDS);
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
        long   startTime  = System.currentTimeMillis();
        try {
            // 执行方法
            return  invoker.invoke(invocation);
        } finally {
            // 保存执行时间
            long current = System.currentTimeMillis();
            long cost = current - startTime;
            InvokeTime invokeTime = new InvokeTime(current, cost);
            invokeTimes.add(invokeTime);
        }

    }
}
